
#include "hal_flash.h"

static const flash_st pfls_array[FLASH_NUM] =
{
	{0x00801990u,0x300},
	{0x008019A1u,0x300},
	{0x00800000u,0x300}
};

static const flash_st cfls_array[FLASH_NUM] = 
{
	{0x00001990u,0x300},
	{0x00001980u,0x300},
	{0x00003990u,0x300}
};

uint8_t temp[PAGE_SIZE] = {0};

/*
static const flash_sector cfls_sector[8]=
{
	{CFLASH_LMS_LSL0,CFLASH_SECTOR0_START,CFLASH_SECTOR0_SIZE},
	{CFLASH_LMS_LSL1,CFLASH_SECTOR1_START,CFLASH_SECTOR1_SIZE},
	{CFLASH_LMS_LSL2,CFLASH_SECTOR2_START,CFLASH_SECTOR2_SIZE},
	{CFLASH_LMS_LSL3,CFLASH_SECTOR3_START,CFLASH_SECTOR3_SIZE},
	{CFLASH_LMS_LSL4,CFLASH_SECTOR4_START,CFLASH_SECTOR4_SIZE},
	{CFLASH_LMS_LSL5,CFLASH_SECTOR5_START,CFLASH_SECTOR5_SIZE},
	{CFLASH_LMS_MSL0,CFLASH_SECTOR6_START,CFLASH_SECTOR6_SIZE},
	{CFLASH_LMS_MSL1,CFLASH_SECTOR7_START,CFLASH_SECTOR7_SIZE}
};

static void hal_GetSector(flash_sector *sector ,uint32_t addr ,uint32_t len,uint32_t *cfls, uint32_t *num)
{ 
	uint8_t i =0;
	uint8_t sector_num = 0;
	uint8_t sector_index = 0;
	for(i = 0; i < 8; i++)
	{
		if((addr <= sector[i].flash_startaddr + sector[i].flash_size))
		{
			sector_index = i;
			break;
		}
	}
	if(i == 8)
	{
		*cfls = 0;
		*num = 0;
	}
	else
	{
		if(len != 0)
		{
			for(i = sector_index; i < 8; ++i)
			{
				sector_num ++;
				if(len > sector[i].flash_size)
				{
					len -=sector[i].flash_size;
				}
				else
				{
					break;
				}
			}
			*cfls = sector[sector_index].flash_lsl;
			*num = sector_num;
		}
		else
		{
			*cfls = sector[sector_index].flash_lsl;
			*num = 0;
		}
	}
}
*/

result_en hal_pfls_init(void)
{
	//CFlash_AC_Init();
	return HAL_SUCCEED;
}

result_en hal_pfls_erase(flash_index_en index ,uint32_t len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t result = 0;
	uint32_t i = 0;
	uint32_t start_addr = 0;
	uint32_t end_addr = 0;
	if(((pfls_array[index].tgt_addr + len -1) >= PFLASH_END_ADDR) || (len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
		/* Flash must be unlocked before it can be erased and programmed */
		DFlash_UnlockBlocksInit();
		/* Flash Select Block Cancel */
		DFlash_BlockSelect_Cancel();
		
		start_addr = pfls_array[index].tgt_addr;
		end_addr = start_addr + len - 1;
		for(i = start_addr - (start_addr %(PAGE_SIZE));start_addr < (end_addr + PAGE_SIZE) ;)
		{
			result = DFlash_PageErase(i);
			if(result != 0)
			{
				flash_re = HAL_FAIL;
				break;
			}
			i += PAGE_SIZE;
			start_addr += PAGE_SIZE;
		}
	}
	return flash_re;
}

result_en hal_pfls_read(flash_index_en index ,uint8_t * buff ,uint32_t len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t start_addr = 0;
	uint32_t i = 0;
	if(((pfls_array[index].tgt_addr + len -1) >= PFLASH_END_ADDR) || (len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
		/* Flash must be unlocked before it can be erased and programmed */
		DFlash_UnlockBlocksInit();
		/* Flash Select Block Cancel */
		DFlash_BlockSelect_Cancel();
		
		start_addr = pfls_array[index].tgt_addr;
		for(i = 0; i < len; ++i)
		{
			buff[i] = DFlash_ByteRead(start_addr);
			start_addr++;
		}
		flash_re = HAL_SUCCEED;
	}
	return flash_re;
}

result_en hal_pfls_erase_write(flash_index_en index ,const uint8_t *buff ,uint32_t erase_len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t i = 0;
	uint32_t read_temp = 0;
	uint32_t result = 0;
	uint32_t start_addr = 0;
	uint32_t end_addr = 0;
	uint32_t write_addr = 0;
	uint32_t buff_index = 0;
	
	if(((pfls_array[index].tgt_addr + erase_len -1) >= PFLASH_END_ADDR) || (erase_len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
		/* Flash must be unlocked before it can be erased and programmed */
		DFlash_UnlockBlocksInit();
		/* Flash Select Block Cancel */
		DFlash_BlockSelect_Cancel();
		
		start_addr = pfls_array[index].tgt_addr;
		end_addr = start_addr + erase_len - 1;
		for(i = start_addr - (start_addr %(PAGE_SIZE));i < end_addr ; i += PAGE_SIZE)
		{
			for(read_temp = 0; read_temp < PAGE_SIZE ; ++read_temp)
			{
				if((i + read_temp) < start_addr)
				{
					temp[read_temp] = CFlash_ByteRead(i+read_temp);
				}
				else if((i + read_temp) > end_addr)
				{
					temp[read_temp] = CFlash_ByteRead(i+read_temp);
				}
				else
				{
					temp[read_temp] = buff[buff_index++];
				}
			}
			result = DFlash_PageErase(i);
			if(result != 0)
			{
				flash_re = HAL_FAIL;
				break;
			}
			result = DFlash_Program(i ,PAGE_SIZE,(const uint32_t *)temp);
			if(result != 0)
			{
				flash_re = HAL_FAIL;
				break;
			}
		}
	}
	
	return flash_re;
}

result_en hal_pfls_write(flash_index_en index ,const uint8_t *buff ,uint32_t len)
{	
	result_en flash_re = HAL_SUCCEED;
	uint32_t result = 0;
	uint32_t write_len = len;
	if(((pfls_array[index].tgt_addr + len -1) >= PFLASH_END_ADDR) || (write_len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
		/* Flash must be unlocked before it can be erased and programmed */
		DFlash_UnlockBlocksInit();
		/* Flash Select Block Cancel */
		DFlash_BlockSelect_Cancel();
		
		result = DFlash_Program(pfls_array[index].tgt_addr , write_len , (const uint32_t *)buff);
		if(result != 0)
		{
			flash_re = HAL_FAIL;
		}
	}
	return flash_re;
}

flash_compare_en hal_pfls_compare(flash_index_en index ,const uint8_t *buff ,uint32_t len)
{
	flash_compare_en flash_re = FLASH_SAME;
	uint32_t result = 0;
	uint32_t i = 0;
	uint32_t start_addr = 0;
	if(((pfls_array[index].tgt_addr + len -1) >= PFLASH_END_ADDR) || (len == 0))
	{
		flash_re = FLASH_DIFFERENT;
	}
	else
	{
		/* Flash must be unlocked before it can be erased and programmed */
		DFlash_UnlockBlocksInit();
		/* Flash Select Block Cancel */
		DFlash_BlockSelect_Cancel();
		
		start_addr = pfls_array[index].tgt_addr;
		for(i = 0 ;i < len ; ++i)
		{
			if(buff[i] != DFlash_ByteRead(start_addr+i))
			{
				flash_re = FLASH_DIFFERENT;
				break;
			}
		}
	}
	return flash_re;
}

result_en hal_pfls_blank_check(flash_index_en index ,uint32_t len)
{
	flash_compare_en flash_re = HAL_SUCCEED;
	uint32_t result = 0;
	uint32_t i = 0;
	uint32_t start_addr = 0;
	if(((pfls_array[index].tgt_addr + len -1) >= PFLASH_END_ADDR) || (len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    DFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    DFlash_BlockSelect_Cancel();
	    
		start_addr = pfls_array[index].tgt_addr;
		for(i = 0 ;i < len ; ++i)
		{
			if(0xff != DFlash_ByteRead(start_addr+i))
			{
				flash_re = HAL_FAIL;
				break;
			}
		}
	}
	return flash_re;	
}



result_en hal_cfls_init(void)
{
	CFlash_AC_Init();
}

result_en hal_cfls_erase(flash_index_en index ,uint32_t len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t result = 0;
	uint32_t i = 0;
	uint32_t start_addr = 0;
	uint32_t end_addr = 0;
	if(((cfls_array[index].tgt_addr + len -1) >= CFLASH_END_ADDR) || (len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    CFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    CFlash_BlockSelect_Cancel();
	    
		start_addr = cfls_array[index].tgt_addr;
		end_addr = start_addr + len - 1;
		for(i = start_addr - (start_addr %(PAGE_SIZE));start_addr < (end_addr + PAGE_SIZE) ;)
		{
			result = CFlash_PageErase(i);
			if(result != 0)
			{
				flash_re = HAL_FAIL;
				break;
			}
			i += PAGE_SIZE;
			start_addr += PAGE_SIZE;
		}
	}
	return flash_re;
}

result_en hal_cfls_read(flash_index_en index ,uint8_t *buff ,uint32_t len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t start_addr = 0;
	uint32_t i = 0;
	if(((cfls_array[index].tgt_addr + len -1) >= CFLASH_END_ADDR) || (len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    CFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    CFlash_BlockSelect_Cancel();
	    
		start_addr = cfls_array[index].tgt_addr;
		for(i = 0; i < len; ++i)
		{
			buff[i] = CFlash_ByteRead(start_addr);
			start_addr++;
		}
		flash_re = HAL_SUCCEED;
	}
	return flash_re;
}

result_en hal_cfls_rease_write(flash_index_en index ,const uint8_t *buff ,uint32_t erase_len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t i = 0;
	uint32_t read_temp = 0;
	uint32_t result = 0;
	uint32_t start_addr = 0;
	uint32_t end_addr = 0;
	uint32_t write_addr = 0;
	uint32_t buff_index = 0;
	
	if(((cfls_array[index].tgt_addr + erase_len -1) >= CFLASH_END_ADDR) || (erase_len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    CFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    CFlash_BlockSelect_Cancel();
	    
		start_addr = cfls_array[index].tgt_addr;
		end_addr = start_addr + erase_len - 1;
		for(i = start_addr - (start_addr %(PAGE_SIZE));i < (end_addr + PAGE_SIZE) ; i += PAGE_SIZE)
		{
			for(read_temp = 0; read_temp < PAGE_SIZE ; ++read_temp)
			{
				if((i + read_temp) < start_addr)
				{
					temp[read_temp] = CFlash_ByteRead(i+read_temp);
				}
				else if((i + read_temp) > end_addr)
				{
					temp[read_temp] = CFlash_ByteRead(i+read_temp);
				}
				else
				{
					temp[read_temp] = buff[buff_index++];
				}
			}
			result = CFlash_PageErase(i);
			if(result != 0)
			{
				flash_re = HAL_FAIL;
				break;
			}
			result = CFlash_Program(i ,PAGE_SIZE,(const uint32_t *)temp);
			if(result != 0)
			{
				flash_re = HAL_FAIL;
				break;
			}
		}
	}
	
	return flash_re;
}

result_en hal_cfls_write(flash_index_en index ,const uint8_t *buff , uint32_t len)
{
	result_en flash_re = HAL_SUCCEED;
	uint32_t result = 0;
	uint32_t write_len = len;
	if(((cfls_array[index].tgt_addr + len -1) >= CFLASH_END_ADDR) || (write_len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    CFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    CFlash_BlockSelect_Cancel();
	    
		result = CFlash_Program(cfls_array[index].tgt_addr , write_len , (const uint32_t *)buff);
		if(result != 0)
		{
			flash_re = HAL_FAIL;
		}
	}
	return flash_re;
}

flash_compare_en hal_cfls_compare(flash_index_en index ,const uint8_t *buff ,uint32_t len)
{
	flash_compare_en flash_re = FLASH_SAME;
	uint32_t result = 0;
	uint32_t i = 0;
	uint32_t start_addr = 0;
	if(((cfls_array[index].tgt_addr + len -1) >= CFLASH_END_ADDR) || (len == 0))
	{
		flash_re = FLASH_DIFFERENT;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    CFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    CFlash_BlockSelect_Cancel();
	    
		start_addr = cfls_array[index].tgt_addr;
		for(i = 0 ;i < len ; ++i)
		{
			if(buff[i] != CFlash_ByteRead(start_addr+i))
			{
				flash_re = FLASH_DIFFERENT;
				break;
			}
		}
	}
	return flash_re;
}

result_en hal_cfls_blank_check(flash_index_en index ,uint32_t len)
{
	flash_compare_en flash_re = HAL_SUCCEED;
	uint32_t result = 0;
	uint32_t i = 0;
	uint32_t start_addr = 0;
	if(((cfls_array[index].tgt_addr + len -1) >= CFLASH_END_ADDR) || (len == 0))
	{
		flash_re = HAL_FAIL;
	}
	else
	{
	    /* Flash must be unlocked before it can be erased and programmed */
	    CFlash_UnlockBlocksInit();
	    /* Flash Select Block Cancel */
	    CFlash_BlockSelect_Cancel();
	    
		start_addr = cfls_array[index].tgt_addr;
		for(i = 0 ;i < len ; ++i)
		{
			if(0xff != CFlash_ByteRead(start_addr+i))
			{
				flash_re = HAL_FAIL;
				break;
			}
		}
	}
	return flash_re;
}

